home *** CD-ROM | disk | FTP | other *** search
/ Super PC 34 / Super PC 34 (Shareware).iso / spc / UTIL / DJGPP2 / V2 / DJLSR200.ZIP / src / libc / crt0 / mcount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-05  |  4.3 KB  |  187 lines

  1. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  2. #include <libc/stubs.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <fcntl.h>
  7. #include <signal.h>
  8. #include <setjmp.h>
  9. #include <sys/time.h>
  10. #include <sys/exceptn.h>
  11.  
  12. /* header of a GPROF type file
  13. */
  14. typedef struct {
  15.   long low;
  16.   long high;
  17.   long nbytes;
  18. } header;
  19.  
  20. /* entry of a GPROF type file
  21. */
  22. typedef struct {
  23.     unsigned long from;
  24.     unsigned long to;
  25.     unsigned long count;
  26. } MTABE;
  27.  
  28. /* internal form - sizeof(MTAB) is 4096 for efficiency
  29. */
  30. typedef struct MTAB {
  31.   MTABE calls[341];
  32.   struct MTAB *prev;
  33. } MTAB;
  34.  
  35. static header h;
  36. static short *histogram;
  37. static int mcount_skip = 1;
  38. static int histlen;
  39. static MTAB *mtab=0;
  40.  
  41. /* called by functions.  Use the pointer it provides to cache
  42. ** the last used MTABE, so that repeated calls to/from the same
  43. ** pair works quickly - no lookup.
  44. */
  45. void mcount(int _to);
  46. void mcount(int _to)
  47. {
  48.   MTAB *m;
  49.   int i;
  50.   int to;
  51.   int ebp;
  52.   int from;
  53.   int mtabi;
  54.   MTABE **cache;
  55.  
  56.   mcount_skip = 1;
  57.   asm("movl %%edx,%0" : "=g" (cache)); /* obtain the cached pointer */
  58.   to = *((&_to)-1) - 12;
  59.   ebp = *((&_to)-2); /* glean the caller's return address from the stack */
  60.   from = ((int *)ebp)[1];
  61.   if (*cache && ((*cache)->from == from) && ((*cache)->to == to))
  62.   {
  63.     /* cache paid off - works quickly */
  64.     (*cache)->count++;
  65.     mcount_skip = 0;
  66.     return;
  67.   }
  68.  
  69.   /* no cache hit - search all mtab tables for a match, or an empty slot */
  70.   mtabi = -1;
  71.   for (m=mtab; m; m=m->prev)
  72.   {
  73.     for (i=0; i<341; i++)
  74.     {
  75.       if (m->calls[i].from == 0)
  76.       {
  77.         /* empty slot - end of table */
  78.         mtabi = i;
  79.         break;
  80.       }
  81.       if ((m->calls[i].from == from) &&
  82.           (m->calls[i].to == to))
  83.         {
  84.           /* found a match - bump count and return */
  85.           m->calls[i].count ++;
  86.           *cache = m->calls + i;
  87.           mcount_skip = 0;
  88.           return;
  89.         }
  90.     }
  91.   }
  92.   if (mtabi != -1)
  93.   {
  94.     /* found an empty - fill it in */
  95.     mtab->calls[mtabi].from = from;
  96.     mtab->calls[mtabi].to = to;
  97.     mtab->calls[mtabi].count = 1;
  98.     *cache = mtab->calls + mtabi;
  99.     mcount_skip = 0;
  100.     return;
  101.   }
  102.   /* lob off another page of memory and initialize the new table */
  103.   m = (MTAB *)sbrk(sizeof(MTAB));
  104.   memset(m, 0, sizeof(MTAB));
  105.   m->prev = mtab;
  106.   mtab = m;
  107.   m->calls[0].from = from;
  108.   m->calls[0].to = to;
  109.   m->calls[0].count = 1;
  110.   *cache = m->calls;
  111.   mcount_skip = 0;
  112. }
  113.  
  114. /* this is called during program exit (installed by atexit). */
  115. static void
  116. mcount_write(void)
  117. {
  118.   MTAB *m;
  119.   int i, f;
  120.   struct itimerval new_values;
  121.  
  122.   mcount_skip = 1;
  123.  
  124.   /* disable timer */
  125.   new_values.it_value.tv_usec = new_values.it_interval.tv_usec = 0;   
  126.   new_values.it_value.tv_sec = new_values.it_interval.tv_sec = 0;
  127.   setitimer(ITIMER_PROF, &new_values, NULL);
  128.  
  129.   f = open("gmon.out", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
  130.   write(f, &h, sizeof(header));
  131.   write(f, histogram, histlen);
  132.   for (m=mtab; m; m=m->prev)
  133.   {
  134.     for (i=0; i<341; i++)
  135.       if (m->calls[i].from == 0)
  136.         break;
  137.     write(f, m->calls, i*12);
  138.   }
  139.   close(f);
  140. }
  141.  
  142. extern unsigned start __asm__ ("start");
  143. #define START (unsigned)&start
  144. extern int etext;
  145.  
  146. /* ARGSUSED */
  147. static void
  148. mcount_tick(int _x)
  149. {
  150.   unsigned bin;
  151.   
  152.   if(!mcount_skip) {
  153.     bin = __djgpp_exception_state->__eip;
  154.     if(bin >= START && bin <= (unsigned)&etext) {
  155.       bin = (bin - START) / 4;    /* 4 EIP's per bin */
  156.       histogram[bin]++;
  157.     }
  158.   }
  159. }
  160.  
  161. /* this is called to initialize profiling before the program starts */
  162. void _mcount_init(void);
  163. void
  164. _mcount_init(void)
  165. {
  166.   struct itimerval new_values;
  167.  
  168.   h.low = START;
  169.   h.high = (int)&etext;
  170.   histlen = (h.high-h.low)/4*sizeof(short);
  171.   h.nbytes = sizeof(header) + histlen;
  172.   histogram = (short *)sbrk(histlen);
  173.   memset(histogram, 0, histlen);
  174.   atexit(mcount_write);
  175.  
  176.   /* here, do whatever it takes to initialize the timer interrupt */
  177.   signal(SIGPROF, mcount_tick);
  178.  
  179.   /* 18.2 tics per second */
  180.   new_values.it_value.tv_usec = new_values.it_interval.tv_usec = 5494;
  181.   new_values.it_value.tv_sec = new_values.it_interval.tv_sec = 0;
  182.  
  183.   setitimer(ITIMER_PROF, &new_values, NULL);
  184.  
  185.   mcount_skip = 0;
  186. }
  187.